import os
import fmt
import path
import parker.util
import syscall
import strings
import parker.log as *

u8 version1 = 1
u8 version2 = 2
string v1_default_system = 'freezer'
string procs_system = 'cgroup.procs'
string parker_dir = 'parker'

type cgroup_t = struct {
    string id
    u8 version
    string path
    string procs_path
    var register = fn(self s, int pid) {
        var pid_str = fmt.sprintf('%d\n', pid)
        var fd = syscall.open(s.procs_path, syscall.O_WRONLY|syscall.O_APPEND, 0)

        syscall.write(fd, pid_str as [u8])
        syscall.close(fd)
    }
    var clear = fn(self s) {
        logf('s.procs_path is "%s"', s.procs_path)

        var fd = syscall.open(s.procs_path, syscall.O_RDONLY, 0) catch err {
            throw fmt.sprintf('open procs path="%s" failed: %s', s.procs_path, err.msg)
        }
        var stat = syscall.fstat(fd)
        var buf = vec<u8>{len=stat.size}
        var len = syscall.read(fd, buf)
        if len == 0 {
            logf('no pids in cgroup=%s', s.procs_path)
        } else {
            logf('read pids from cgroup, %s', buf as string)
            var pids = strings.split(buf as string, '\n')

            for pid_str in pids {
                // str to int
                var pid = strtol(pid_str.ref(), 0, 10)
                if pid == 0 {
                    throw fmt.sprintf('pid str %s to int failed', pid_str)
                }
                
                // kill by pid
                syscall.kill(pid, syscall.SIGKILL) catch err {
                    logf('kill pid %d failed %s', pid, err.msg)
                }
            }
        }
    
       // 清理 cgroup 目录
       os.rmdir(s.path, true)
    }

}

fn make():cgroup_t {
    if !path.exists('/sys/fs/cgroup') {
        throw 'cgroup new err=' + 'path /sys/fs/cgroup not found'
    }
    
    u8 version = 0
    
    if path.exists('/sys/fs/cgroup/cgroup.controllers') {
        version = version2
    }  else if path.exists(path.join("/sys/fs/cgroup", v1_default_system)) {
        version = version1
    } else {
        throw 'cannot detect cgroup version'
    }

    var id = util.rand_letter(32)
    
    var cgroup_path = ''
    if version == version1 {
        cgroup_path = path.join('/sys/fs/cgroup', v1_default_system, parker_dir, id)
    } else {
        cgroup_path = path.join('/sys/fs/cgroup', parker_dir, id)
    }

    var procs_path = path.join(cgroup_path, procs_system)

    // mkdir all
    os.mkdirs(cgroup_path, 0755)

    return cgroup_t {
        id = id,
        version = version,
        path = cgroup_path,
        procs_path = procs_path
    }
}
